#include <webx/menu.h>
#include <webx/route.h>
#include <http/HttpHelper.h>
#include <dbentity/T_XG_CONF.h>
#include <dbentity/T_XG_DBETC.h>

class ExecModule : public webx::ProcessBase
{
protected:
	int process();
};

HTTP_WEBCGI(CGI_PROTECT, "${filename}")
DEFINE_HTTP_CGI_EXPORT_FUNC(ExecModule)

static HttpServer* app = HttpServer::Instance();

static bool SystemCommand(char cmd)
{
	return stdx::async([cmd](){
		static char* data = app->getShareData()->data;

		data[0] = cmd;
		data[1] = '-';

		Socket().connect(app->getHost(), app->getPort());
	});
}

EXTERN_DLL_FUNC int HttpPluginInit(IHttpServer* app)
{
	return XG_OK;
}

int ExecModule::process()
{
	param_string(cmd);
    param_string(type);
	param_string(name);

	webx::CheckSystemRight(this);

	int res = 0;
	string root = app->getPath();

	stdx::tolower(cmd);
	stdx::tolower(type);

	auto get = [&](const string& type){
		HostItem route = webx::GetRegCenterHost();

		if (route.host.empty()) stdx::Throw(XG_SYSERR, "route center not found");

		HttpRequest request;

		if (type == "database")
		{
			request.init("getdatabaseList");
			request.setParameter("id", name);
		}
		else if (type == "confile")
		{
			request.init("confile/sharenote");
			request.setParameter("flag", "Q");
			request.setParameter("title", name);
		}
		else
		{
			stdx::Throw(XG_PARAMERR, "invalid parameter[type]");
		}

		SmartBuffer data = request.getResult(route.host, route.port);

		if (data.str())
		{
			JsonElement json(data.str());

			if (json.isObject()) return json;
		}

		stdx::Throw(XG_NETERR, "request[" + type + "] failed");

		return json;
	};

	auto sync = [&](const string& type){
		int num = 0;
		sp<DBConnect> dbconn = webx::GetDBConnect();

		if (type == "confile")
		{
			auto synconfile = [&](){
				JsonElement json = get(type);

				string title = json["title"].asString();
				string folder = json["folder"].asString();
				string content = json["content"].asString();

				if (dbconn->execute("UPDATE T_XG_CONF SET CONTENT=? WHERE FOLDER=? AND TITLE=?", content, folder, title) < 0)
				{
					LogTrace(eERR, "sync configure[confile][%s] failed", title.c_str());
				}
				else
				{
					LogTrace(eIMP, "sync configure[confile][%s] success", title.c_str());

					sp<Session> session = webx::GetLocaleSession("SYSTEM_CONFILE");

					if (session) session->remove(title);

					++num;
				}
			};

			if (name.empty())
			{
				sp<QueryResult> rs = dbconn->query("SELECT TITLE FROM T_XG_CONF WHERE FOLDER='WEBPAGE'");

				if (rs)
				{
					sp<RowData> row = rs->next();

					while (row)
					{
						name = row->getString(0);

						row = rs->next();

						synconfile();
					}
				}
			}
			else
			{
				synconfile();
			}
		}
		else
		{
			JsonElement json = get(type);

			json = json.get("list");

			CHECK_FALSE_RETURN(json.isArray());

			for (auto item : json)
			{
				string id = item["id"].asString();

				if (name.empty() || id == name)
				{
					CT_XG_DBETC tab;

					tab.init(dbconn);

					for (auto tmp : item)
					{
						string key = tmp.getName();

						tab.setValue(stdx::toupper(key), tmp.asString());
					}

					if (tab.update() < 0)
					{
						LogTrace(eERR, "sync configure[database][%s] failed", id.c_str());

						return false;
					}

					LogTrace(eIMP, "sync configure[database][%s] success", id.c_str());

					typedef DBConnectPool* (*GetDBConnectPoolFunc)(const char*);

					static GetDBConnectPoolFunc getPool = (GetDBConnectPoolFunc)Process::GetObject("HTTP_GET_DBCONNECT_POOL");

					if (tab.find() && tab.next() && tab.enabled.val() > 0)
					{
						DBConnectPool* pool = getPool(id.c_str());

						if (pool)
						{
							ConfigFile cfg;
							string key = "DLLPATH_" + tab.type.val();
							string path = webx::GetParameter(stdx::toupper(key));

							if (path.empty())
							{
								path = stdx::tolower(tab.type.val());
								path = stdx::translate("$PRODUCT_HOME/dll/libdbx." + path + "pool.so");
							}

							cfg.setVariable("DLLPATH", path);
							cfg.setVariable("HOST", tab.host.val());
							cfg.setVariable("USER", tab.user.val());
							cfg.setVariable("NAME", tab.name.val());
							cfg.setVariable("PORT", (int)tab.port.val());
							cfg.setVariable("CHARSET", tab.charset.val());
							cfg.setVariable("PASSWORD", tab.passwd.val());

							pool->init(cfg);
						}

						++num;
					}
				}
			}
		}

		return true;
	};

	if (cmd == "get")
	{
		out << get(type);

		return XG_OK;
	}
	else if (cmd == "sync")
	{
		res = 0;

		if (type.empty())
		{
			if (sync("database")) res++;
			if (sync("confile")) res++;
		}
		else
		{
			if (sync(type)) res++;
		}

		if (res == 0) stdx::Throw(XG_ERROR, "sync configure failed");

		webx::ReloadSystemConfig();
	}
	else if (cmd == "call")
	{
		param_int(async);
		param_string(path);
		param_string(param);

		webx::CheckFilePath(path);

		if (async > 0)
		{
			res = stdx::async([=](){
				webx::GetRemoteResult(path, param);
			}) ? XG_OK : XG_SYSBUSY;
		}
		else
		{
			SmartBuffer data = webx::GetRemoteResult(path, param);

			if (data.isNull()) return simpleResponse(XG_SYSERR);

			clearResponse();

			out << data.str();

			return data.size();
		}
	}
	else if (cmd == "updatemodule")
	{
		param_string(src);
		param_string(dest);

		if (src.length() < 7) return simpleResponse(XG_PARAMERR);

		if (memcmp(src.c_str(), "http://", 7) == 0)
		{
			XFile file;
			SmartBuffer data = HttpHelper::GetResult(src);

			if (data.size() < 0xFF) return simpleResponse(XG_ERROR);

			src = "/dat/" + stdx::GetFileNameFromPath(dest);

			file.open(root + src, eCREATE);

			if (file.write(data.str(), data.size()) < 0) return simpleResponse(XG_ERROR);
		}

		src = root + src;
		src = stdx::replace(src, "\\", "/");
		src = stdx::replace(src, "//", "/");

		if (GetPathType(src.c_str()) == eFILE)
		{
			param_int(port);
			param_string(host);
			param_string(flag);

			if (host.length() > 0)
			{
				string path;
				HttpRequest request(getClassName());

				if (flag == "R")
				{
					src = src.substr(root.length());
				}
				else
				{
					char* addrlist[32];

					if (GetLocalAddress(addrlist) <= 0) return simpleResponse(XG_ERROR);

					path = root + "dat/pub/" + stdx::GetFileNameFromPath(src);

					rename(src.c_str(), path.c_str());

					src = path.substr(root.length());
					src = HttpHelper::GetLink(src, addrlist[0], app->getPort());
				}

				request.setParameter("cmd", cmd);
				request.setParameter("src", src);
				request.setParameter("dest", dest);

				SmartBuffer data = request.getResult(host, port);

				if (path.length() > 0) RemoveFile(path.c_str());

				if (data.isNull()) return simpleResponse(XG_ERROR);

				out << data.str();

				return XG_OK;
			}

			dest = root + dest;
			dest = stdx::replace(dest, "\\", "/");
			dest = stdx::replace(dest, "//", "/");

			stdx::async([=](){
				app->updateModuleFile(src, dest);
			});

			Sleep(100);
		}
	}
	else
	{
		param_int(port);
		param_string(host);

		if (host.length() > 0)
		{
			HttpRequest request(getClassName());

			request.setParameter("cmd", cmd);

			SmartBuffer data = request.getResult(host, port);

			if (data.isNull()) return simpleResponse(XG_ERROR);

			out << data.str();

			return XG_OK;
		}

		if (cmd == "exit")
		{
			res = SystemCommand('k') ? XG_OK : XG_ERROR;
		}
		else if (cmd == "reload")
		{
			res = SystemCommand('r') ? XG_OK : XG_ERROR;
		}
		else if (cmd == "restart")
		{
			res = SystemCommand('s') ? XG_OK : XG_ERROR;
		}
		else
		{
			stdx::Throw(XG_PARAMERR, "invalid parameter[cmd]");
		}
	}

	json["datetime"] = DateTime::ToString();
	json["code"] = res;
	out << json;

	return XG_OK;
}